AWS Client VPN のリソースとパラメータを一枚絵にまとめつつ過去のエントリもまとめてみた
コンバンハ、千葉(幸)です。
まずはこちらをご覧ください。
はい。
Client VPN を設計・構築する上で意識すべきリソースとパラメータを表してみました。
あとはこの図をベースに、過去の Developers.IO のエントリを引用しながら AWS Client VPN について説明していきます。
手っ取り早く Client VPN 博士になりましょう。
先に補足
- 全てのパラメータを網羅しているわけではなく、カスタマーが設定を意識するところをメインに取り上げています
- 図中で点線になっているパラメータはオプション(指定が必須ではない)であるものを表します
クライアント VPN エンドポイント
AWS Client VPN のメインとなるコンポーネントです。
ドキュメントはこちら。
AWS CLI による参照結果の例は以下のとおりです。
{ "ClientVpnEndpoints": [ { "ClientVpnEndpointId": "cvpn-endpoint-123456789123abcde", "Description": "Endpoint for Admin access", "Status": { "Code": "available" }, "CreationTime": "2020-11-13T11:37:27", "DnsName": "*.cvpn-endpoint-123456789123abcde.prod.clientvpn.ap-south-1.amazonaws.com", "ClientCidrBlock": "172.31.0.0/16", "DnsServers": [ "8.8.8.8" ], "SplitTunnel": false, "VpnProtocol": "openvpn", "TransportProtocol": "udp", "VpnPort": 443, "ServerCertificateArn": "arn:aws:acm:ap-south-1:123456789012:certificate/a1b2c3d4-5678-90ab-cdef-11111EXAMPLE", "AuthenticationOptions": [ { "Type": "certificate-authentication", "MutualAuthentication": { "ClientRootCertificateChain": "arn:aws:acm:ap-south-1:123456789012:certificate/a1b2c3d4-5678-90ab-cdef-22222EXAMPLE" } } ], "ConnectionLogOptions": { "Enabled": true, "CloudwatchLogGroup": "Client-vpn-connection-logs", "CloudwatchLogStream": "cvpn-endpoint-123456789123abcde-ap-south-1-2020/11/13-FCD8HEMVaCcw" }, "Tags": [ { "Key": "Name", "Value": "Client VPN" } ], "SecurityGroupIds": [ "sg-aabbcc11223344567" ], "VpcId": "vpc-a87f92c1", "SelfServicePortalUrl": "https://self-service.clientvpn.amazonaws.com/endpoints/cvpn-endpoint-123456789123abcde", "ClientConnectOptions": { "Enabled": false } } ] }
順番に一貫性はありませんが、いくつかパラメータをかいつまんで説明します。
クライアント IPv4 CIDR
Client VPN エンドポイントとの接続が確立された際に、クライアントに割り振られる IP のレンジを定義します。
ブロックサイズが /22 以上、/12 以下である必要があります。
アドレス範囲の一部は Client VPN エンドポイントの可用性モデルをサポートするために使用され、クライアントに割り当てられません。想定される最大同時接続数の2倍程度がまかなえるような範囲を指定することが推奨されています。
また、ここでの CIDR は Client VPN ルートの宛先の値と重複してはいけません。手動で追加するルートはもちろんのこと、デフォルトで「エンドポイントを関連づける VPC」の CIDR も宛先として追加されるため、そことは異なるものを指定する必要があります。
各種注意事項は以下を確認してください。
一度作成した後は変更ができないパラメータのため、ご注意ください。
サーバー証明書
Client VPN エンドポイントは様々な認証タイプに対応していますが、そのいずれを選択する場合でもサーバー証明書が必要となります。
証明書は ACM にプロビジョニングされている必要があり、その ARN を指定することになります。
サーバー証明書発行の手順はこちらを参考に。
証明書ってなんで必要なの?となったらこちらを。
認証タイプ
以下のいずれかから選択可能です。
- 証明書ベース
- 相互認証
- ユーザーベース
- Active Directory 認証
- 統合(フェデレーション)認証
証明書ベースとユーザーベースの認証は併用可能です。(ユーザーベース同士は不可)
併用しているパターンの例は以下を参照ください。
相互認証
相互認証のパターンでは、サーバー証明書に加え、クライアント証明書を作成する必要があります。クライアントごとに異なるものを用意するか、どのように配布するかなどを考慮する必要が出てきます。
Client VPN エンドポイントにクライアント証明書 ARN を設定する際、一定の条件においてはサーバー証明書と同一の ARN を指定することができます。
条件とは、「サーバー証明書とクライアント証明書の発行機関(CA)が同じであること」です。詳細は以下エントリを参照ください。
Windows クライアントでの証明書の作成例は以下を。
また、一部の機能(セルフサービスポータル、承認ルールでの特定のユーザー指定など)は相互認証では対応していないことに注意してください。
ユーザーが組織を離れた場合などに、そのユーザーが使用していたクライアント証明書を無効化したい(エンドポイントへの接続を拒否したい)、という場合はクライアント証明書失効リストという仕組みを使用します。
Active Directory 認証
Active Directory の認証情報を使用して Client VPN に接続可能になります。平たく言えば、VPN クライアントでドメインユーザーのユーザー名とパスワードを入力することでエンドポイントに接続できるようになります。
認証先として指定できるのは AWS Directory Service の各種ディレクトリタイプです。
- Simple AD
- Managed Microsoft AD
- AD Connector
Simple AD を利用した場合の例。
Managed Microsoft AD を使用した例。
AD Connector を使用した例。
統合(フェデレーション)認証
SAML 2.0 経由のフェデレーション認証を行うこともできます。 IAM SAML プロバイダーの ARN を設定することになります。
セルフサービスポータル 用のプロバイダー ARN を追加することもできます。
セルフサービスポータル
ユーザーベース認証を使用する場合に使用できる機能です。
VPN の構成ファイルや VPN クライアントをダウンロードできるポータルを、エンドユーザーに提供できます。
接続ログ
有効化するか否かを選択できます。有効化した場合、出力先の CloudWatch Logs ロググループ(およびストリーム名)を指定します。
出力されるログのイメージは以下です。
{ "connection-log-type": "connection-attempt", "connection-attempt-status": "successful", "connection-reset-status": "NA", "connection-attempt-failure-reason": "NA", "connection-id": "cvpn-connection-abc123abc123abc12", "client-vpn-endpoint-id": "cvpn-endpoint-aaa111bbb222ccc33", "transport-protocol": "udp", "connection-start-time": "2020-03-26 20:37:15", "connection-last-update-time": "2020-03-26 20:37:15", "client-ip": "10.0.1.2", "common-name": "client1", "device-type": "mac", "device-ip": "98.247.202.82", "port": "50096", "ingress-bytes": "0", "egress-bytes": "0", "ingress-packets": "0", "egress-packets": "0", "connection-end-time": "NA" }
クライアント接続ハンドラ
クライアントがエンドポイントに接続を試みる際に、その可否を判断するロジックを含めることができます。ロジックの判断を行う Lambda 関数をあらかじめ定義しておき、その ARN をここで指定できます。接続のタイミングで Lambda 関数が呼び出され、クライアントの属性などを基に接続可否を返却します。
特定の IP アドレスからのみ接続を許可する、特定の時間帯は接続をブロックする、といった操作が可能です。
カスタム DNS サーバー
ここで DNS サーバーの IP アドレスを指定すると、Client VPN の接続が確立した際に、クライアントに対してその設定がプッシュされます。つまり、「 Client VPN に接続している間はこの DNS サーバーを参照する」という挙動を実現できます。
接続確立後にもクライアントから DNS サーバーに対してアクセス可能なよう、各種 経路・設定にはご注意ください。
スプリットトンネル
スプリットトンネルは、Client VPN との トンネル確立時にクライアントデバイスにプッシュされるルートテーブルをコントロールする機能です。
デフォルトでは無効になっており、その場合、デフォルトルートが Client VPN を向くようにクライアントデバイスのルートテーブルが書き換えられます。つまり、すべてのトラフィックが Client VPN を経由します。
有効にすると、 Client VPN ルートテーブルに存在する宛先のみが、クライアントデバイスのルートテーブルに追加されます。例えば、 VPC CIDR のみが Client VPN ルートの宛先として定義されていた場合、クライアントデバイスからのトラフィックは以下のような経路を辿ります。
- VPC CIDR 内の IP に対するトラフィックは Client VPN トンネル経由
- それ以外(例えばインターネットへの経路)はトンネルを経由せず、デバイスが元々持っていた経路
トランスポートプロトコル
UDP か TCP を選択できます。デフォルトでは UDP が選択されます。
通常、 TCP より UDP の方が優れたパフォーマンスが出ます。エンドポイント作成後に変更はできませんので注意してください。
VPN ポート
443 か 1194 を選択できます。
1194 って何のポートだ?と思って調べたところ、openvpn のポートでした。
VPC ID
Client VPN エンドポイントを関連づける VPC を指定します。一つのエンドポイントで複数の VPC を指定することはできません。
また、後続で設定するターゲットネットワークはここで指定した VPC 内のサブネットである必要があります。
セキュリティグループ
Client VPN エンドポイントを作成し、ターゲットネットワークとの関連づけを行うと、サブネット内に ENI が作成されます( Client VPN ENI )。その ENI に関連づけるセキュリティグループをここで指定できます。
複数指定することもできますし、指定しないこともできます。指定しない場合、 VPC の default のセキュリティグループが適用されます。なるべくなら明示的に専用のものを指定しましょう。
ちなみに、ここで指定するセキュリティグループにおいて、インバウンドは開放する必要がありません。逆に言うと、ここでインバウンドを絞っても送信元を制御することはできません。あくまでアウトバウンドを制御するためのものです。
クライアントからのトラフィックは Client VPN ENI で送信元 NAT され、宛先に到達します。 「 ENI から宛先」のアウトバウンドトラフィックが、セキュリティグループのアウトバウンド設定により制御されます。
このあたりの詳細は以下エントリをご参照ください。
クライアントが使用するパブリック IP に対して送信元制限をかけたい、となった場合には、先述のクライアント接続ハンドラを使用する必要があります。
ターゲットネットワーク
この辺りです。
ここまでの説明でもチラチラ出てきましたが、簡単に取り上げます。
ドキュメントはこちら。
AWS CLI による参照結果の例は以下のとおり。
{ "ClientVpnTargetNetworks": [ { "AssociationId": "cvpn-assoc-012e837060753dc3d", "VpcId": "vpc-11111222222333333", "TargetNetworkId": "subnet-0123456789abcabca", "ClientVpnEndpointId": "cvpn-endpoint-123456789123abcde", "Status": { "Code": "associating" }, "SecurityGroups": [ "sg-012345678910abcab" ] } ] }
ターゲットネットワークは、 Client VPN と関連づける形で作成します。関連づけを行ったサブネットの数に応じて料金が発生します。
ターゲットネットワークの対象となるサブネットは、 Client VPN エンドポイントを関連づけた VPC の中から選択する必要があります。また、複数選択する場合は、サブネットが異なる AZ に属している必要があります。(つまり AZ ごとに一つまで。)
そして、対象となるサブネットは /27 以上のサイズであり、空き IP が 8 個以上ある必要があります。ターゲットネットワーク専用のサブネットを作成しておくのが管理しやすいでしょう。
承認ルール
この辺りです。
承認ルール(Authorization rules)は、Client VPN を介してアクセスできるネットワーク、およびユーザーを制御するためのファイアウォールとして機能するコンポーネントです。
ドキュメントはこちら。
AWS CLI による参照例はこちら。
{ "AuthorizationRules": [ { "ClientVpnEndpointId": "cvpn-endpoint-123456789123abcde", "GroupId": "", "AccessAll": true, "DestinationCidr": "0.0.0.0/0", "Status": { "Code": "active" } } ] }
承認ルールも Client VPN エンドポイントと関連づけることで機能します。一つの宛先 CIDR ごとに承認ルールを作成します。一つの Client VPN に対して複数の承認ルールを設定できます。
デフォルトでは承認ルールが存在しないため、Client VPN に接続してもそこを経由してどこにもアクセスできない、という状態です。
宛先の CIDR
Client VPN 経由でアクセスしたい宛先の CIDR を設定します。大抵のケースにおいて、ひとまず VPC の CIDR を指定した承認ルールを作成することになるでしょう。
VPC 経由でインターネットに接続したい場合には 0.0.0.0/0 を、対向のオンプレ環境やピアリング先の VPC などへのルートを確立したい場合はそれらの CIDR を指定します。
VPC CIDR より狭い範囲で指定することもできます。
対象ユーザー
宛先の CIDR ごとに、そこへのアクセスを許可するユーザーを定義します。
厳密には、まず「すべてにアクセス(AccessAll)」が有効か無効かを選択します。デフォルトでは有効となり、ユーザーごとの制御は行われません。
証明書ベースの認証である相互認証のみを使用している場合には、ここを無効化することはできません。ユーザーベース認証のいずれかを使用している場合に、「すべてにアクセス」を無効化することができます。
無効化した場合、合わせてアクセスグループ ID を入力する必要があります。
Active Directory 認証であれば AD グループの SID 、統合認証であれば SAML ベースの Idp で定義されたグループ ID/名前 が該当します。
クライアント VPN ルート
最後のリソースです。
確認するのはこの辺りです。
ドキュメントはこちら。
AWS CLI による参照例はこちら。
{ "Routes": [ { "ClientVpnEndpointId": "cvpn-endpoint-123456789123abcde", "DestinationCidr": "10.0.0.0/16", "TargetSubnet": "subnet-0123456789abcabca", "Type": "Nat", "Origin": "associate", "Status": { "Code": "active" }, "Description": "Default Route" }, { "ClientVpnEndpointId": "cvpn-endpoint-123456789123abcde", "DestinationCidr": "0.0.0.0/0", "TargetSubnet": "subnet-0123456789abcabca", "Type": "Nat", "Origin": "add-route", "Status": { "Code": "active" } } ] }
いわゆるルートテーブルです。Client VPN ENI が所属するサブネットのサブネットルートテーブルとはまた別物で、その前段でのルートを決定するものです。
ターゲットネットワークの関連づけを行うと、自動的に以下のルートが追加されます。
- 宛先の CIDR : VPC CIDR(ターゲットネットワークが所属するもの)
- ターゲット:ターゲットネットワーク
上記以外のルートを追加したい( VPC 外のリソースにもアクセスしたい)場合には、手動でルート追加することになります。
順番が前後しますが、先にターゲットの方を説明します。
ターゲット
基本的にはターゲットネットワークを指定します。一つのルートでは一つのターゲットネットワークしか選択できないため、ターゲットネットワークが複数ある場合にはそれぞれに対して作成します。
0.0.0.0/0 へのルートを追加したい、となったら、ルートを二つ作成する、ということです。
宛先 | ターゲット |
---|---|
0.0.0.0/0 | ターゲットネットワーク A |
0.0.0.0/0 | ターゲットネットワーク C |
ここで、複数のターゲットネットワーク間でルートが一致するよう意識する必要があります。例えば上の表において 1 行目のルートのみを定義していた場合、不都合が生じます。
クライアントが Client VPN エンドポイントに接続する際に、どちらのターゲットネットワークを経由するかを選択することはできません。0.0.0.0/0 向けのルートがないターゲットネットワーク C に割り振られた場合、そこに対してアクセスできない、という事象が発生します。たまたまターゲットネットワーク A に割り振られた時はアクセスできる、という不安定な状態となるのを避けるため、ルートを一致させる必要があるというわけです。
そしてターゲットネットワーク以外にもターゲットとして指定できるものがあります。それはローカルです。これは先日のアップデートで有効になったクライアント間の通信を実現する際に指定するものです。
ルート送信先
宛先の CIDR のことですが、マネジメントコンソールからルートを作成する際にはこのような表記になるため、それにあわせてみました。
改めて言うほどのものでもないですが、VPC 外部への通信を行う場合は、ここできちんと定義しておく必要があります。(クライアント間の通信の場合は「クライアント IPv4 CIDR」がルート送信先となります。)
承認ルール、セキュリティグループ、サブネットルートテーブルなどと合わせて適切にアクセスが行えるか意識する必要があります。
また、スプリットトンネルが有効の場合には、ここで定義したルート送信先がクライアントデバイスにプッシュされます。クライアントデバイスが処理できるルート数を考慮しておくとよいでしょう。
終わりに
というわけで冒頭の図の再掲です。
ここまで来たら皆さんも立派な Client VPN 博士ですね。
本エントリに載せきれなかったものもあるので、更なる立派な博士になりたい方は以下をご参照ください。
以上、千葉(幸)がお送りしました。